// <copyright file="EALInstruction.cs" company="Codeplex project Eco.Contrib"> 
// The MIT License (MIT) 
// </copyright> 
// <author>Peter Buchmann</author> 

namespace Eco.Contrib
{
    using System;
    using System.Collections.Generic;
    using Eco.ObjectRepresentation;
    using Eco.Services;
    using Eco.UmlCodeAttributes;

    /// <summary>
    /// EALInstruction: Executes a EAL instruction
    /// </summary>
    public partial class EalInstruction
    {
        /// <summary>
        /// Executes the function.
        /// </summary>
        /// <param name="serviceProvider">The service provider.</param>
        /// <param name="variableList">The variable list.</param>
        /// <returns>Return value of executed function</returns>
        [UmlElement(Id = "bc20b613-3ff7-4e0d-9ad0-82e88d0461fc")]
        protected internal override IElement ExecuteFunction(IEcoServiceProvider serviceProvider, IModifiableVariableList variableList)
        {
            if (serviceProvider == null)
            {
                throw new EslException("Parameter is null");
            }
            
            IActionLanguageService actionLanguageService = serviceProvider.GetEcoService<IActionLanguageService>();
            IElement element = actionLanguageService.Evaluate(OCL, variableList);
            SetVariable(serviceProvider, variableList, element);
            return element;
        }

        /// <summary>
        /// Inits the specified tokens.
        /// </summary>
        /// <param name="tokens">The tokens.</param>
        [UmlElement(Id = "5442801f-6ccd-4c6c-8b86-8291fd6281d8")]
        protected internal override void Init(Dictionary<IList<EslToken>, Type> tokens)
        {
            if (tokens == null)
            {
                throw new EslException("Parameter is null");
            }

            List<EslToken> tokenList = new List<EslToken>();
            tokenList.Add(new EslToken(EslTokenType.Word, "Eal"));
            tokenList.Add(new EslToken(EslTokenType.Operator, "("));
            tokens.Add(tokenList, this.GetType());
            tokenList = new List<EslToken>();
            tokenList.Add(new EslToken(EslTokenType.Word, "%"));
            tokenList.Add(new EslToken(EslTokenType.Operator, ":="));
            tokenList.Add(new EslToken(EslTokenType.Word, "Eal"));
            tokenList.Add(new EslToken(EslTokenType.Operator, "("));
            tokens.Add(tokenList, this.GetType());
            tokenList = new List<EslToken>();
            tokenList.Add(new EslToken(EslTokenType.Word, "%"));
            tokenList.Add(new EslToken(EslTokenType.Operator, ":="));
            tokens.Add(tokenList, this.GetType());
            tokenList = new List<EslToken>();
            tokens.Add(tokenList, this.GetType());
        }

        /// <summary>
        /// Parses the specified token list.
        /// </summary>
        /// <param name="tokenList">The token list.</param>
        /// <param name="ecoScript">The eco script.</param>
        /// <param name="fullExpression">if set to <c>true</c> [full expression].</param>
        [UmlElement(Id = "3b9c4ae0-3cdb-41cf-8461-390411ce3901")]
        protected internal override void Parse(IList<EslToken> tokenList, EcoScript ecoScript, bool fullExpression)
        {
            if (tokenList == null || ecoScript == null)
            {
                throw new EslException("Parameter is null");
            }

            EslToken token = GetNextToken(tokenList);
            RememberEcoScript(ecoScript, token);
            EslToken tokenOperator = GetNextToken(tokenList);

            if ((token.TokenType == EslTokenType.Word) &&
                 (tokenOperator.TokenType == EslTokenType.Operator) && (tokenOperator.TokenValue == ":="))
            {
                ResultVariable = new Variable(this.ServiceProvider());
                ResultVariable.Name = token.TokenValue;
                token = GetNextToken(tokenList);
                tokenOperator = GetNextToken(tokenList);
            }

            bool withEal = true;
            int openParenthesis = 1;
            if ((token.TokenType != EslTokenType.Word) || (token.TokenValue.ToLower(System.Globalization.CultureInfo.CurrentCulture) != "eal"))
            {
                tokenList.Insert(0, tokenOperator);
                tokenList.Insert(0, token);
                if (!fullExpression)
                {
                    throw new EslException("Keyword EAL expected at " + token.ToString(), token);
                }

                withEal = false;
                openParenthesis = 0;
            }

            EslToken firstToken = null;
            bool finished = false;
            do
            {
                token = GetNextToken(tokenList);
                if (firstToken == null)
                {
                    firstToken = token;
                }

                if (token.TokenType == EslTokenType.Operator)
                {
                    if (token.TokenValue == "(")
                    {
                        openParenthesis++;
                    }

                    if (token.TokenValue == ")")
                    {
                        openParenthesis--;
                    }
                }

                finished = (withEal && (openParenthesis == 0)) ||
                       (!withEal && (openParenthesis == 0) &&
                        (((token.TokenType == EslTokenType.Operator) && (token.TokenValue == ";")) ||
                         (token.TokenType == EslTokenType.End)));
            } 
            while (!finished);

            OCL = ecoScript.GetTextBetweenTokens(firstToken, MyTokens[MyTokens.Count - 1]);

            if (withEal && fullExpression)
            {
                EslToken tokenEnd = GetNextToken(tokenList);
                AssertInstructionEnd(tokenEnd);
            }
        }
    }
}